﻿Imports System.Text

Namespace SqlCe35
    Public Class TableFactory
        Inherits TableFactoryBase

        ''' <summary>
        ''' 読み込み、生成処理の関数を示します。
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>差し替え可能です。</remarks>
        Public Shared Property Creater As Action(Of Type, Action(Of ColumnDefinitionAttribute)) = AddressOf (New Kairyu.Extensions.DDL.SqlCe35.ColumnDefinitionAttributeFactory).Create

        Protected Overrides Sub CreateCore(cn As IDbConnection, ts As IEnumerable(Of Type))
            Dim fn As Func(Of String, InfoLevelEnum, IDbCommand) =
                Function(s, lv)
                    Dim cmd As IDbCommand = cn.CreateCommand
                    cmd.CommandText = s
                    Log.OnExecuteCommand.Invoke(Nothing, New CreateDbCommandEventArgs(cmd) With {.CommandInfoLevel = lv})
                    Return cmd
                End Function

            For Each item In ts
                Dim def As TableDefinition = TableDefinitionReader.Read(item, Creater)
                If def.ColumnDefinisions.Any = False Then Continue For

                Dim cmd As IDbCommand = fn.Invoke(Me.GetExistsTableCommandText(def), InfoLevelEnum.Warn)
                If cmd.ExecuteScalar <> 0 Then
                    fn.Invoke(Me.GetDropTableCommandText(def), InfoLevelEnum.Warn).ExecuteNonQuery()
                End If

                fn.Invoke(Me.GetCreateTableCommandText(def), InfoLevelEnum.Warn).ExecuteNonQuery()
            Next
        End Sub

        Private Function GetExistsTableCommandText(def As TableDefinition) As String
            Return String.Format("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE (TABLE_NAME = '{0}')", def.Table.TableName)
        End Function

        Private Function GetDropTableCommandText(def As TableDefinition) As String
            Return String.Format("DROP TABLE {0}", def.Table.TableName)
        End Function

        Private Function GetCreateTableCommandText(def As TableDefinition) As String
            Return String.Format("CREATE TABLE {0} ({1})", def.Table.TableName, CreateColumnDefinitionText(def))
        End Function

        Private Function CreateColumnDefinitionText(def As TableDefinition)
            Dim s As String = String.Empty
            Dim add As Action(Of String) =
                Sub(text)
                    If String.IsNullOrEmpty(text) Then Return
                    If String.IsNullOrEmpty(s) = False Then s &= ", "
                    s &= text
                End Sub

            '列
            For Each item In def.ColumnDefinisions
                add.Invoke(item.ColumnFullText)
            Next

            '制約
            add.Invoke(Me.CreatePrimaryKeyDefinitionText(def))
            add.Invoke(Me.CreateUniqueDefinitionText(def))

            Return s
        End Function

        Private Function CreatePrimaryKeyDefinitionText(def As TableDefinition) As String
            Dim s As String = String.Empty
            Dim add As Action(Of String) =
                Sub(text)
                    If String.IsNullOrEmpty(s) = False Then s &= ", "
                    s &= text
                End Sub

            For Each item In (From el In def.ColumnDefinisions Where el.Column.IsPrimaryKey Order By el.Index)
                add.Invoke(item.Column.ColumnName)
            Next

            Return If(String.IsNullOrEmpty(s), s, String.Format("CONSTRAINT PK_{0} PRIMARY KEY({1})", def.Table.PlainTableName, s))
        End Function

        Private Function CreateUniqueDefinitionText(def As TableDefinition) As String
            Dim s As String = String.Empty
            Dim add As Action(Of String) =
                Sub(text)
                    If String.IsNullOrEmpty(s) = False Then s &= ", "
                    s &= text
                End Sub

            For Each item In (From el In def.ColumnDefinisions Where el.Column.IsAlternativeLoadKey Order By el.Index)
                add.Invoke(item.Column.ColumnName)
            Next

            Return If(String.IsNullOrEmpty(s), s, String.Format("CONSTRAINT UQ_{0} UNIQUE ({1})", def.Table.PlainTableName, s))
        End Function

    End Class

End Namespace

